package com.dw.controller;



import cn.hutool.core.lang.UUID;
import com.fasterxml.jackson.core.JsonProcessingException;

import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RBloomFilter;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;

import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Slf4j
@RestController
@RequestMapping("/product")
public class LockTestController {

    @Autowired
    StringRedisTemplate stringRedisTemplate;

    @Autowired
    private RedisTemplate<String , Object> redisTemplate;

    @Autowired
    RedissonClient redissonClient;


    @GetMapping("/bloomtest")
    public void bloomtest()  {
        RBloomFilter<String> bloomFilter =redissonClient.getBloomFilter("mybloom");
        bloomFilter.tryInit(1000,0.01);//布隆过滤器的bit位长度  , 误判率大小hash的个数
        //初始化
        bloomFilter.add("aaa");
        bloomFilter.add("bbb");
        bloomFilter.add("ccc");
        bloomFilter.add("ddd");
        bloomFilter.add("eee");
        log.info("aaa is contains {}", bloomFilter.contains("aaa"));
        log.info("fff is contains {}", bloomFilter.contains("fff"));
    }


    /**
     * 没有锁
     * @throws JsonProcessingException
     */
    @GetMapping("/nolock_inc")
    public void nolock_inc() throws JsonProcessingException {
        ValueOperations<String, Object> opsForValue = redisTemplate.opsForValue();
        int num = 0;
        if(opsForValue.get("num")==null){
            num = 0;
        }else{
            num = (int)opsForValue.get("num");
            num ++;
        }
        opsForValue.set("num",num);
        System.out.println(num);
    }

    /**
     * 同步锁
     * @throws JsonProcessingException
     */
    @GetMapping("/syslock_inc")
    public void syslock_inc() throws JsonProcessingException {
        ValueOperations<String, Object> opsForValue = redisTemplate.opsForValue();
        int num = 0;
        synchronized ("lock") {
            if (opsForValue.get("num") == null) {
                num = 0;
            } else {
                num = (int) opsForValue.get("num"); //
                num++;
            }
            opsForValue.set("num", num);
        }
        System.out.println(num);
    }

    //redis 实现
    @GetMapping("/uselock_inc1")
    public void uselock_inc1() throws JsonProcessingException, InterruptedException {
        ValueOperations<String, Object> opsForValue = redisTemplate.opsForValue();
        String lockName = "lock";
        String lockValue = UUID.randomUUID().toString();
        //Boolean flag = opsForValue.setIfAbsent(lockName, lockValue, 5, TimeUnit.SECONDS);
        while (true) {
            // 尝试获取锁
            Boolean flag = opsForValue.setIfAbsent(lockName, lockValue, 5, TimeUnit.SECONDS);
            if (Boolean.TRUE.equals(flag)) {
                break; // 获取成功，跳出循环
            }
            // 获取失败，睡眠一会再试
            //Thread.sleep(1000);
        }

        int num;
        if (opsForValue.get("num") == null) {
            num = 1;
        } else {
            num = (int) opsForValue.get("num"); //
            num++;
        }
        opsForValue.set("num", num);

        //        redisTemplate.delete("lock");

        //------------------------Lua释放锁--------------------
       String script =
                "if redis.call('get', KEYS[1]) == ARGV[1] then " +
                        "   return redis.call('del', KEYS[1]) " +
                        "else " +
                        "   return 0 " +
                        "end";

        // 创建RedisScript对象
        DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>();
        redisScript.setScriptText(script);
        redisScript.setResultType(Long.class);

        // 执行脚本
        List<String> keys = Arrays.asList(lockName);
        Long result = redisTemplate.execute(redisScript, keys, lockValue);

        if (result == 1) {
            System.out.println("锁释放成功");
        } else {
            System.out.println("锁释放失败（可能已超时或不是自己的锁）");
        }
        System.out.println(num);
    }

    //redisson 实现
    @GetMapping("/uselock_inc")
    public void uselock_inc() throws JsonProcessingException {
        ValueOperations<String, Object> opsForValue = redisTemplate.opsForValue();
        RLock lock = redissonClient.getLock("mylock");
        lock.lock();
        int num = 0;
        if(opsForValue.get("num")==null){
            num = 1;
        }else{
            num = (int)opsForValue.get("num"); //
            num ++;
        }

        opsForValue.set("num",num);//默认序列化用的是java,不支持跨语言
        lock.unlock();
        System.out.println(num);
    }
}
